#pragma once
#include "logger.hpp"
#include <fstream>
#include <string>
#include <random>
#include <ios>
#include <sstream>
#include <iomanip>

namespace shared {

class Uuid
{
public:
    // 生成一个16位随机字符组成的字符串
    static std::string createUuid()
    {
        // 1. 生成6个[0, 255]随机数字(即1字节数据 == 16进制字符) == 共生成12位16进制的字符
        std::random_device rd;          // 用于生成随机数
        static std::mt19937 generator(rd());   // 随机数范围: 2^19937
        static std::uniform_int_distribution<int> distribution(0, 255);  // 限定数据范围
        std::stringstream ss;
        for(int i = 0; i < 6; ++i) {
            if(i == 2) ss << '-';
            ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator);
        }
        ss << "-";

        // 2. 生成2字节的编号数字 == 共生成4位16进制数字字符
        static std::atomic<short> idx(0);
        short tmp = idx.fetch_add(1);
        ss << std::setw(2) << std::setfill('0') << std::hex << tmp;
        return ss.str();
    }
};

class VerifyCode
{
public:
    // 生成6个[0, 9]随机数字
    static std::string generate()
    {
        std::random_device rd;                  // 用于生成随机数
        static std::mt19937 generator(rd());    // 随机数周期: 2^19937
        static std::uniform_int_distribution<int> distribution(0, 9);  // 限定数据范围
        std::stringstream ss;
        for(int i = 0; i < 6; ++i) {
            ss << distribution(generator);
        }
        return ss.str();
    }
};

class FileUtil
{
public:
    static bool exists(const std::string& filename)
    {
        struct stat st;
        return stat(filename.c_str(), &st) == 0;   // On success, zero is returned
    }

    static bool read(const std::string& filename, std::string& body)
    {
        std::ifstream ifs(filename, std::ios::binary | std::ios::in | std::ios::ate);   // ate定位文件尾
        if(!ifs.is_open()) {
            LOG_ERROR("打开文件 {} 失败！", filename);
            return false;
        }
        uint64_t len = ifs.tellg();     // 获取当前偏移量 == 文件大小
        ifs.seekg(0, std::ios::beg);
        body.resize(len);
        ifs.read(&body[0], len);
        if(ifs.fail()) {
            LOG_ERROR("读取文件 {} 数据失败！", filename);
            ifs.close();
            return false;
        }
        ifs.close();
        return true;
    }
    static bool write(const std::string& filename, const std::string& body)
    {
        std::ofstream ofs(filename, std::ios::out | std::ios::binary | std::ios::trunc);
        if (!ofs.is_open()) {
            LOG_ERROR("打开文件 {} 失败！", filename);
            return false;
        }
        ofs.write(body.data(), body.size());
        if(ofs.fail()) {
            LOG_ERROR("写入文件 {} 失败！", filename);
            ofs.close();
            return false;
        }
        ofs.close();
        return true;
    }
    static std::string getFileMd5Sum(const std::string& filepath) 
    {
        if (!exists(filepath)) {
            return std::string();
        }
        
        std::string command = fmt::format(R"(md5sum "{}")", filepath);
        FILE* pipe = popen(command.c_str(), "r");
        if (!pipe) return std::string();
        
        char buffer[128];
        std::string result;
        while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
            result += buffer;
        }
        pclose(pipe);
        
        // 提取纯MD5值
        size_t idx = result.rfind(' ');
        if (idx != std::string::npos) {
            return result.substr(0, idx);
        }
        return result;
    }
};

}